/*
 * @[H]:  Copyright (c) 2021 Phytium Information Technology, Inc. 
 * 
 *  SPDX-License-Identifier: Apache-2.0. 
 * 
 * @Date: 2021-07-19 21:44:27
 * @LastEditTime: 2021-08-25 09:45:44
 * @Description:  Description of file
 * @Modify History: 
 * * * Ver   Who        Date         Changes
 * * ----- ------     --------    --------------------------------------
 */

#include "f_xmac_hw.h"
#include "f_xmac.h"
#include "ft_assert.h"

/*****************************************************************************/
/**
 * Set the MAC address for this driver/device.  The address is a 48-bit value.
 * The device must be stopped before calling this function.
 *
 * @param instance_p is a pointer to the instance to be worked on.
 * @param address_ptr is a pointer to a 6-byte MAC address.
 * @param index is a index to which MAC (1-4) address.
 *
 * @return
 * - FT_SUCCESS if the MAC address was set successfully
 * - FXMAC_STATUS_IS_STARTED if the device has not yet been stopped
 *
 *****************************************************************************/
LONG FXmacSetMacAddress(FXmac *instance_p, void *address_ptr, u8 index)
{
    u32 MacAddr;
    u8 *aptr = (u8 *)(void *)address_ptr;
    u8 index_loc = index;
    LONG status;
    FT_ASSERTNONVOID(instance_p != NULL);
    FT_ASSERTNONVOID(aptr != NULL);
    FT_ASSERTNONVOID(instance_p->is_ready == (u32)FT_COMPONENT_IS_READY);
    FT_ASSERTNONVOID((index_loc < (u8)FXMAC_MAX_MAC_ADDR));

    /* Be sure device has been stopped */
    if (instance_p->is_started == (u32)FT_COMPONENT_IS_STARTED)
    {
        status = (LONG)(FXMAC_STATUS_IS_STARTED);
    }
    else
    {

        /* Set the MAC bits [31:0] in BOT */
        MacAddr = *(aptr);
        MacAddr |= ((u32)(*(aptr + 1)) << 8U);
        MacAddr |= ((u32)(*(aptr + 2)) << 16U);
        MacAddr |= ((u32)(*(aptr + 3)) << 24U);
        FXMAC_WRITEREG32(instance_p->config.base_address,
                         ((u32)FXMAC_GEM_SA1B + ((u32)index_loc * (u32)8)), MacAddr);

        /* There are reserved bits in TOP so don't affect them */
        MacAddr = FXMAC_READREG32(instance_p->config.base_address,
                                  ((u32)FXMAC_GEM_SA1T + ((u32)index_loc * (u32)8)));

        MacAddr &= (u32)(~FXMAC_GEM_SAB_MASK);

        /* Set MAC bits [47:32] in TOP */
        MacAddr |= (u32)(*(aptr + 4));
        MacAddr |= (u32)(*(aptr + 5)) << 8U;

        FXMAC_WRITEREG32(instance_p->config.base_address,
                         ((u32)FXMAC_GEM_SA1T + ((u32)index_loc * (u32)8)), MacAddr);

        status = (LONG)(FT_SUCCESS);
    }
    return status;
}

/**
 * @name: 
 * @msg:  
 * @return {*}
 * @param {FXmac} *mac is a pointer to the instance to be worked on.
 * @param {void} *address_ptr is an output parameter, and is a pointer to a buffer into
 *        which the current MAC address will be copied.
 * @param {u8} index is a index to which MAC (0-3) address.
 */
void FXmacGetMacAddress(FXmac *instance_p, void *address_ptr, u8 index)
{
    u32 reg_value;
    u8 *ptr = (u8 *)address_ptr;
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(ptr != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTVOID((index < FXMAC_MAX_MAC_ADDR));

    reg_value = FXMAC_READREG32(instance_p->config.base_address, FXMAC_GEM_SA1B + ((u32)index * (u32)8));
    *ptr = (u8)reg_value;
    *(ptr + 1) = (u8)(reg_value >> 8U);
    *(ptr + 2) = (u8)(reg_value >> 16U);
    *(ptr + 3) = (u8)(reg_value >> 24U);

    reg_value = FXMAC_READREG32(instance_p->config.base_address, FXMAC_GEM_SA1T + ((u32)index * (u32)8));
    *ptr = (u8)reg_value;
    *ptr = (u8)reg_value;
    *(ptr + 1) = (u8)(reg_value >> 8U);
}

/*****************************************************************************/
/**
 * Set the Type ID match for this driver/device.  The register is a 32-bit
 * value. The device must be stopped before calling this function.
 *
 * @param instance_p is a pointer to the instance to be worked on.
 * @param id_check is type ID to be configured.
 * @param Index is a index to which Type ID (1-4).
 *
 * @return
 * - FT_SUCCESS if the MAC address was set successfully
 * - FXMAC_STATUS_IS_STARTED if the device has not yet been stopped
 *
 *****************************************************************************/
LONG FXmacSetTypeIdCheck(FXmac *instance_p, u32 id_check, u8 Index)
{
    u8 index_loc = Index;
    LONG status;
    FT_ASSERTNONVOID(instance_p != NULL);
    FT_ASSERTNONVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTNONVOID((index_loc < (u8)FXMAC_MAX_TYPE_ID));

    /* Be sure device has been stopped */
    if (instance_p->is_started == (u32)FT_COMPONENT_IS_STARTED)
    {
        status = (LONG)(FXMAC_STATUS_IS_STARTED);
    }
    else
    {

        /* Index ranges 1 to 4, for offset calculation is 0 to 3. */

        /* Set the ID bits in MATCHx register */
        FXMAC_WRITEREG32(instance_p->config.base_address,
                         ((u32)FXMAC_MATCH1_OFFSET + ((u32)index_loc * (u32)4)), id_check);

        status = (LONG)(FT_SUCCESS);
    }
    return status;
}

void FXmacSetOperatingSpeed(FXmac *instance_p, u32 speed)
{
    u32 reg_value;

    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == FT_COMPONENT_IS_READY);
    FT_ASSERTVOID((speed == FXMAC_SPEED_100) || (speed == FXMAC_SPEED_1000) || (speed == FXMAC_SPEED_2500) || (speed == FXMAC_SPEED_10000));

    if ((instance_p->config.interface == FXMAC_PHY_INTERFACE_MODE_USXGMII) || (instance_p->config.interface == FXMAC_PHY_INTERFACE_MODE_XGMII))
    {
        if (speed == FXMAC_SPEED_10000)
        {
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_SRC_SEL_LN, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL0_LN, 0x4);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL1_LN, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_PMA_XCVR_POWER_STATE, 0x1);
        }
    }
    else if (instance_p->config.interface == FXMAC_PHY_INTERFACE_MODE_SGMII)
    {
        if (speed == FXMAC_SPEED_2500)
        {
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_SRC_SEL_LN, 0);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL0_LN, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL1_LN, 0x2);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_PMA_XCVR_POWER_STATE, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL0, 0);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL1, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL2, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL0, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL1, 0x0);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3_0, 0x0); /*0x1c70*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL4_0, 0x0); /*0x1c74*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL3_0, 0x0); /*0x1c78*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL4_0, 0x0); /*0x1c7c*/
        }
        else if (speed == FXMAC_SPEED_1000)
        {
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_SRC_SEL_LN, 0);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL0_LN, 0x4);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL1_LN, 0x8);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_PMA_XCVR_POWER_STATE, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL0, 0x0);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL1, 0x0);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL2, 0x0);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL0, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL1, 0x0);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3_0, 0x0); /*0x1c70*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL4_0, 0x0); /*0x1c74*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL3_0, 0x0); /*0x1c78*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL4_0, 0x0); /*0x1c7c*/
        }
        else if (speed == FXMAC_SPEED_100)
        {
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_SRC_SEL_LN, 0x0);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL0_LN, 0x4);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_DIV_SEL1_LN, 0x8);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_PMA_XCVR_POWER_STATE, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL0, 0x0);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL1, 0x0);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL2, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL0, 0x1);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL1, 0x0);
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3_0, 0x1); /*0x1c70*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL4_0, 0x0); /*0x1c74*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL3_0, 0x0); /*0x1c78*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL4_0, 0x1); /*0x1c7c*/
        }
    }
    else if (instance_p->config.interface == FXMAC_PHY_INTERFACE_MODE_RGMII)
    {
        if (speed == FXMAC_SPEED_1000)
        {
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_MII_SELECT, 0x1);       /*0x1c18*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_SEL_MII_ON_RGMII, 0x0); /*0x1c1c*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL0, 0x0);      /*0x1c20*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL1, 0x1);      /*0x1c24*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL2, 0x0);      /*0x1c28*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3, 0x0);      /*0x1c2c*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL0, 0x0);      /*0x1c30*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL1, 0x1);      /*0x1c34*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_CLK_250M_DIV10_DIV100_SEL,
                             0x0);                                                               /*0x1c38*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL5, 0x1);       /*0x1c48*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RGMII_TX_CLK_SEL0, 0x1); /*0x1c80*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RGMII_TX_CLK_SEL1, 0x0); /*0x1c84*/
        }
        else if (speed == FXMAC_SPEED_100)
        {
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_MII_SELECT, 0x1);       /*0x1c18*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_SEL_MII_ON_RGMII, 0x0); /*0x1c1c*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL0, 0x0);      /*0x1c20*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL1, 0x1);      /*0x1c24*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL2, 0x0);      /*0x1c28*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3, 0x0);      /*0x1c2c*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL0, 0x0);      /*0x1c30*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL1, 0x1);      /*0x1c34*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_CLK_250M_DIV10_DIV100_SEL,
                             0x0);                                                               /*0x1c38*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL5, 0x1);       /*0x1c48*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RGMII_TX_CLK_SEL0, 0x0); /*0x1c80*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RGMII_TX_CLK_SEL1, 0x0); /*0x1c84*/
        }
        else
        {
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_MII_SELECT, 0x1);       /*0x1c18*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_SEL_MII_ON_RGMII, 0x0); /*0x1c1c*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL0, 0x0);      /*0x1c20*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL1, 0x1);      /*0x1c24*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL2, 0x0);      /*0x1c28*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_TX_CLK_SEL3, 0x0);      /*0x1c2c*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL0, 0x0);      /*0x1c30*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL1, 0x1);      /*0x1c34*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_CLK_250M_DIV10_DIV100_SEL,
                             0x1);                                                               /*0x1c38*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL5, 0x1);       /*0x1c48*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RGMII_TX_CLK_SEL0, 0x0); /*0x1c80*/
            FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RGMII_TX_CLK_SEL1, 0x0); /*0x1c84*/
        }
    }
    else if (instance_p->config.interface == FXMAC_PHY_INTERFACE_MODE_RMII)
    {
        FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_RX_CLK_SEL5, 0x1); /*0x1c48*/
    }

    /*GEM_HSMAC(0x0050) provide rate to the external*/
    reg_value = FXMAC_READREG32(instance_p->config.base_address, FXMAC_GEM_HSMAC);
    reg_value &= ~(((1 << FXMAC_GEM_HSMACSPEED_SIZE) - 1) << FXMAC_GEM_HSMACSPEED_OFFSET);
    reg_value |= (((speed) & ((1 << FXMAC_GEM_HSMACSPEED_SIZE) - 1)) << FXMAC_GEM_HSMACSPEED_OFFSET);
    FXMAC_WRITEREG32(instance_p->config.base_address, FXMAC_GEM_HSMAC, reg_value);
}

/*****************************************************************************/
/**
 * Set options for the driver/device. The driver should be stopped with
 * FXmacStop() before changing options.
 *
 * @param instance_p is a pointer to the instance to be worked on.
 * @param options are the options to set. Multiple options can be set by OR'ing
 *        XTE_*_options constants together. options not specified are not
 *        affected.
 *
 * @return
 * - FT_SUCCESS if the options were set successfully
 * - FXMAC_STATUS_IS_STARTED if the device has not yet been stopped
 *
 * @note
 * See FXmac.h for a description of the available options.
 *
 *****************************************************************************/
LONG FXmacSetOptions(FXmac *instance_p, u32 options)
{
    u32 Reg;            /* Generic register contents */
    u32 reg_netcfg;     /* Reflects original contents of NET_CONFIG */
    u32 reg_new_netcfg; /* Reflects new contents of NET_CONFIG */
    LONG status;
    FT_ASSERTNONVOID(instance_p != NULL);
    FT_ASSERTNONVOID(instance_p->is_ready == (u32)FT_COMPONENT_IS_READY);

    /* Be sure device has been stopped */
    if (instance_p->is_started == (u32)FT_COMPONENT_IS_STARTED)
    {
        status = (LONG)(FXMAC_STATUS_IS_STARTED);
    }
    else
    {

        /* Many of these options will change the NET_CONFIG registers.
	 * To reduce the amount of IO to the device, group these options here
	 * and change them all at once.
	 */

        /* Grab current register contents */
        reg_netcfg = FXMAC_READREG32(instance_p->config.base_address,
                                     FXMAC_NWCFG_OFFSET);
        reg_new_netcfg = reg_netcfg;

        /*
	 * It is configured to max 1536.
	 */
        if ((options & FXMAC_FRAME1536_OPTION) != 0x00000000U)
        {
            reg_new_netcfg |= (FXMAC_NWCFG_1536RXEN_MASK);
        }

        /* Turn on VLAN packet only, only VLAN tagged will be accepted */
        if ((options & FXMAC_VLAN_OPTION) != 0x00000000U)
        {
            reg_new_netcfg |= FXMAC_NWCFG_NVLANDISC_MASK;
        }

        /* Turn on FCS stripping on receive packets */
        if ((options & FXMAC_FCS_STRIP_OPTION) != 0x00000000U)
        {
            reg_new_netcfg |= FXMAC_NWCFG_FCSREM_MASK;
        }

        /* Turn on length/type field checking on receive packets */
        if ((options & FXMAC_LENTYPE_ERR_OPTION) != 0x00000000U)
        {
            reg_new_netcfg |= FXMAC_NWCFG_LENERRDSCRD_MASK;
        }

        /* Turn on flow control */
        if ((options & FXMAC_FLOW_CONTROL_OPTION) != 0x00000000U)
        {
            reg_new_netcfg |= FXMAC_NWCFG_PAUSEEN_MASK;
        }

        /* Turn on promiscuous frame filtering (all frames are received) */
        if ((options & FXMAC_PROMISC_OPTION) != 0x00000000U)
        {
            reg_new_netcfg |= FXMAC_NWCFG_COPYALLEN_MASK;
        }

        /* Allow broadcast address reception */
        if ((options & FXMAC_BROADCAST_OPTION) != 0x00000000U)
        {
            reg_new_netcfg &= (u32)(~FXMAC_NWCFG_BCASTDI_MASK);
        }

        /* Allow multicast address filtering */
        if ((options & FXMAC_MULTICAST_OPTION) != 0x00000000U)
        {
            reg_new_netcfg |= FXMAC_NWCFG_MCASTHASHEN_MASK;
        }

        /* enable RX checksum offload */
        if ((options & FXMAC_RX_CHKSUM_ENABLE_OPTION) != 0x00000000U)
        {
            reg_new_netcfg |= FXMAC_NWCFG_RXCHKSUMEN_MASK;
        }

        /* Enable jumbo frames */
        if ((options & FXMAC_JUMBO_ENABLE_OPTION) != 0x00000000U)
        {
            reg_new_netcfg |= FXMAC_NWCFG_JUMBO_MASK;
            FXMAC_WRITEREG32(instance_p->config.base_address,
                             FXMAC_JUMBOMAXLEN_OFFSET, FXMAC_RX_BUF_SIZE_JUMBO);
            Reg = FXMAC_READREG32(instance_p->config.base_address,
                                  FXMAC_DMACR_OFFSET);
            Reg &= ~FXMAC_DMACR_RXBUF_MASK;
            Reg |= (((((u32)FXMAC_RX_BUF_SIZE_JUMBO / (u32)FXMAC_RX_BUF_UNIT) +
                      (((((u32)FXMAC_RX_BUF_SIZE_JUMBO %
                          (u32)FXMAC_RX_BUF_UNIT)) != (u32)0)
                           ? 1U
                           : 0U))
                     << (u32)(FXMAC_DMACR_RXBUF_SHIFT)) &
                    (u32)(FXMAC_DMACR_RXBUF_MASK));
            FXMAC_WRITEREG32(instance_p->config.base_address,
                             FXMAC_DMACR_OFFSET, Reg);
            instance_p->max_mtu_size = FXMAC_MTU_JUMBO;
            instance_p->max_frame_size = FXMAC_MTU_JUMBO +
                                         FXMAC_HDR_SIZE + FXMAC_TRL_SIZE;
            instance_p->max_vlan_frame_size = instance_p->max_frame_size +
                                              FXMAC_HDR_VLAN_SIZE;
            instance_p->rx_buf_mask = FXMAC_RXBUF_LEN_JUMBO_MASK;
        }

        if (((options & FXMAC_SGMII_ENABLE_OPTION) != 0x00000000U))
        {
            reg_new_netcfg |= (FXMAC_NWCFG_SGMIIEN_MASK |
                               FXMAC_NWCFG_PCSSEL_MASK);
        }

        /* Officially change the NET_CONFIG registers if it needs to be
	 * modified.
	 */
        if (reg_netcfg != reg_new_netcfg)
        {
            FXMAC_WRITEREG32(instance_p->config.base_address,
                             FXMAC_NWCFG_OFFSET, reg_new_netcfg);
        }

        /* Enable TX checksum offload */
        if ((options & FXMAC_TX_CHKSUM_ENABLE_OPTION) != 0x00000000U)
        {
            Reg = FXMAC_READREG32(instance_p->config.base_address,
                                  FXMAC_DMACR_OFFSET);
            Reg |= FXMAC_DMACR_TCPCKSUM_MASK;
            FXMAC_WRITEREG32(instance_p->config.base_address,
                             FXMAC_DMACR_OFFSET, Reg);
        }

        /* Enable transmitter */
        if ((options & FXMAC_TRANSMITTER_ENABLE_OPTION) != 0x00000000U)
        {
            Reg = FXMAC_READREG32(instance_p->config.base_address,
                                  FXMAC_NWCTRL_OFFSET);
            Reg |= FXMAC_NWCTRL_TXEN_MASK;
            FXMAC_WRITEREG32(instance_p->config.base_address,
                             FXMAC_NWCTRL_OFFSET, Reg);
        }

        /* Enable receiver */
        if ((options & FXMAC_RECEIVER_ENABLE_OPTION) != 0x00000000U)
        {
            Reg = FXMAC_READREG32(instance_p->config.base_address,
                                  FXMAC_NWCTRL_OFFSET);
            Reg |= FXMAC_NWCTRL_RXEN_MASK;
            FXMAC_WRITEREG32(instance_p->config.base_address,
                             FXMAC_NWCTRL_OFFSET, Reg);
        }

        /* The remaining options not handled here are managed elsewhere in the
	 * driver. No register modifications are needed at this time. Reflecting
	 * the option in instance_p->options is good enough for now.
	 */

        /* Set options word to its new value */
        instance_p->options |= options;

        status = (LONG)(FT_SUCCESS);
    }
    return status;
}

/*****************************************************************************/
/**
 * Clear options for the driver/device
 *
 * @param instance_p is a pointer to the instance to be worked on.
 * @param options are the options to clear. Multiple options can be cleared by
 *        OR'ing FXMAC_*_options constants together. options not specified
 *        are not affected.
 *
 * @return
 * - FT_SUCCESS if the options were set successfully
 * - FXMAC_STATUS_IS_STARTED if the device has not yet been stopped
 *
 * @note
 * See xemacps.h for a description of the available options.
 *
 *****************************************************************************/
LONG FXmacClearOptions(FXmac *instance_p, u32 options)
{
    u32 Reg;             /* Generic */
    u32 reg_net_cfg;     /* Reflects original contents of NET_CONFIG */
    u32 reg_new_net_cfg; /* Reflects new contents of NET_CONFIG */
    LONG status;
    FT_ASSERTNONVOID(instance_p != NULL);
    FT_ASSERTNONVOID(instance_p->is_ready == (u32)FT_COMPONENT_IS_READY);

    /* Be sure device has been stopped */
    if (instance_p->is_started == (u32)FT_COMPONENT_IS_STARTED)
    {
        status = (LONG)(FXMAC_STATUS_IS_STARTED);
    }
    else
    {

        /* Many of these options will change the NET_CONFIG registers.
	 * To reduce the amount of IO to the device, group these options here
	 * and change them all at once.
	 */

        /* Grab current register contents */
        reg_net_cfg = FXMAC_READREG32(instance_p->config.base_address,
                                      FXMAC_NWCFG_OFFSET);
        reg_new_net_cfg = reg_net_cfg;

        /* There is only RX configuration!?
	 * It is configured in two different length, up to 1536 and 10240 bytes
	 */
        if ((options & FXMAC_FRAME1536_OPTION) != 0x00000000U)
        {
            reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_1536RXEN_MASK);
        }

        /* Turn off VLAN packet only */
        if ((options & FXMAC_VLAN_OPTION) != 0x00000000U)
        {
            reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_NVLANDISC_MASK);
        }

        /* Turn off FCS stripping on receive packets */
        if ((options & FXMAC_FCS_STRIP_OPTION) != 0x00000000U)
        {
            reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_FCSREM_MASK);
        }

        /* Turn off length/type field checking on receive packets */
        if ((options & FXMAC_LENTYPE_ERR_OPTION) != 0x00000000U)
        {
            reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_LENERRDSCRD_MASK);
        }

        /* Turn off flow control */
        if ((options & FXMAC_FLOW_CONTROL_OPTION) != 0x00000000U)
        {
            reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_PAUSEEN_MASK);
        }

        /* Turn off promiscuous frame filtering (all frames are received) */
        if ((options & FXMAC_PROMISC_OPTION) != 0x00000000U)
        {
            reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_COPYALLEN_MASK);
        }

        /* Disallow broadcast address filtering => broadcast reception */
        if ((options & FXMAC_BROADCAST_OPTION) != 0x00000000U)
        {
            reg_new_net_cfg |= FXMAC_NWCFG_BCASTDI_MASK;
        }

        /* Disallow multicast address filtering */
        if ((options & FXMAC_MULTICAST_OPTION) != 0x00000000U)
        {
            reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_MCASTHASHEN_MASK);
        }

        /* Disable RX checksum offload */
        if ((options & FXMAC_RX_CHKSUM_ENABLE_OPTION) != 0x00000000U)
        {
            reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_RXCHKSUMEN_MASK);
        }

        /* Disable jumbo frames */
        if (((options & FXMAC_JUMBO_ENABLE_OPTION) != 0x00000000U))
        {
            reg_new_net_cfg &= (u32)(~FXMAC_NWCFG_JUMBO_MASK);
            Reg = FXMAC_READREG32(instance_p->config.base_address,
                                  FXMAC_DMACR_OFFSET);
            Reg &= ~FXMAC_DMACR_RXBUF_MASK;
            Reg |= (((((u32)FXMAC_RX_BUF_SIZE / (u32)FXMAC_RX_BUF_UNIT) +
                      (((((u32)FXMAC_RX_BUF_SIZE %
                          (u32)FXMAC_RX_BUF_UNIT)) != (u32)0)
                           ? 1U
                           : 0U))
                     << (u32)(FXMAC_DMACR_RXBUF_SHIFT)) &
                    (u32)(FXMAC_DMACR_RXBUF_MASK));
            FXMAC_WRITEREG32(instance_p->config.base_address,
                             FXMAC_DMACR_OFFSET, Reg);
            instance_p->max_mtu_size = FXMAC_MTU;
            instance_p->max_frame_size = FXMAC_MTU +
                                         FXMAC_HDR_SIZE + FXMAC_TRL_SIZE;
            instance_p->max_vlan_frame_size = instance_p->max_frame_size +
                                              FXMAC_HDR_VLAN_SIZE;
            instance_p->rx_buf_mask = FXMAC_RXBUF_LEN_MASK;
        }

        if (((options & FXMAC_SGMII_ENABLE_OPTION) != 0x00000000U))
        {
            reg_new_net_cfg &= (u32)(~(FXMAC_NWCFG_SGMIIEN_MASK |
                                       FXMAC_NWCFG_PCSSEL_MASK));
        }

        /* Officially change the NET_CONFIG registers if it needs to be
	 * modified.
	 */
        if (reg_net_cfg != reg_new_net_cfg)
        {
            FXMAC_WRITEREG32(instance_p->config.base_address,
                             FXMAC_NWCFG_OFFSET, reg_new_net_cfg);
        }

        /* Disable TX checksum offload */
        if ((options & FXMAC_TX_CHKSUM_ENABLE_OPTION) != 0x00000000U)
        {
            Reg = FXMAC_READREG32(instance_p->config.base_address,
                                  FXMAC_DMACR_OFFSET);
            Reg &= (u32)(~FXMAC_DMACR_TCPCKSUM_MASK);
            FXMAC_WRITEREG32(instance_p->config.base_address,
                             FXMAC_DMACR_OFFSET, Reg);
        }

        /* Disable transmitter */
        if ((options & FXMAC_TRANSMITTER_ENABLE_OPTION) != 0x00000000U)
        {
            Reg = FXMAC_READREG32(instance_p->config.base_address,
                                  FXMAC_NWCTRL_OFFSET);
            Reg &= (u32)(~FXMAC_NWCTRL_TXEN_MASK);
            FXMAC_WRITEREG32(instance_p->config.base_address,
                             FXMAC_NWCTRL_OFFSET, Reg);
        }

        /* Disable receiver */
        if ((options & FXMAC_RECEIVER_ENABLE_OPTION) != 0x00000000U)
        {
            Reg = FXMAC_READREG32(instance_p->config.base_address,
                                  FXMAC_NWCTRL_OFFSET);
            Reg &= (u32)(~FXMAC_NWCTRL_RXEN_MASK);
            FXMAC_WRITEREG32(instance_p->config.base_address,
                             FXMAC_NWCTRL_OFFSET, Reg);
        }

        /* The remaining options not handled here are managed elsewhere in the
	 * driver. No register modifications are needed at this time. Reflecting
	 * option in instance_p->options is good enough for now.
	 */

        /* Set options word to its new value */
        instance_p->options &= ~options;

        status = (LONG)(FT_SUCCESS);
    }
    return status;
}

/*****************************************************************************/
/**
 * Clear the Hash registers for the mac address pointed by address_ptr.
 *
 * @param instance_p is a pointer to the instance to be worked on.
 *
 *****************************************************************************/
void FXmacClearHash(FXmac *instance_p)
{
    FT_ASSERTVOID(instance_p != NULL);
    FT_ASSERTVOID(instance_p->is_ready == (u32)FT_COMPONENT_IS_READY);

    FXMAC_WRITEREG32(instance_p->config.base_address,
                     FXMAC_HASHL_OFFSET, 0x0U);

    /* write bits [63:32] in TOP */
    FXMAC_WRITEREG32(instance_p->config.base_address,
                     FXMAC_HASHH_OFFSET, 0x0U);
}

/*****************************************************************************/
/**
* Write data to the specified PHY register. The Ethernet driver does not
* require the device to be stopped before writing to the PHY.  Although it is
* probably a good idea to stop the device, it is the responsibility of the
* application to deem this necessary. The MAC provides the driver with the
* ability to talk to a PHY that adheres to the Media Independent Interface
* (MII) as defined in the IEEE 802.3 standard.
*
* Prior to PHY access with this function, the user should have setup the MDIO
* clock with FXmacSetMdioDivisor().
*
* @param instance_p is a pointer to the XEmacPs instance to be worked on.
* @param phy_address is the address of the PHY to be written (supports multiple
*        PHYs)
* @param register_num is the register number, 0-31, of the specific PHY register
*        to write
* @param phy_data is the 16-bit value that will be written to the register
*
* @return
*
* - FT_SUCCESS if the PHY was written to successfully. Since there is no error
*   status from the MAC on a write, the user should read the PHY to verify the
*   write was successful.
* - FXMAC_MII_BUSY if there is another PHY operation in progress
*
* @note
*
* This function is not thread-safe. The user must provide mutually exclusive
* access to this function if there are to be multiple threads that can call it.
*
* There is the possibility that this function will not return if the hardware
* is broken (i.e., it never sets the status bit indicating that the write is
* done). If this is of concern to the user, the user should provide a mechanism
* suitable to their needs for recovery.
*
* For the duration of this function, all host interface reads and writes are
* blocked to the current XEmacPs instance.
*
******************************************************************************/
LONG FXmacPhyWrite(FXmac *instance_p, u32 phy_address,
                   u32 register_num, u16 phy_data)
{
    u32 mgtcr;
    volatile u32 ipisr;
    u32 ip_write_temp;
    LONG status;

    FT_ASSERTNONVOID(instance_p != NULL);

    /* Make sure no other PHY operation is currently in progress */
    if ((!(FXMAC_READREG32(instance_p->config.base_address,
                           FXMAC_NWSR_OFFSET) &
           FXMAC_NWSR_MDIOIDLE_MASK)) == TRUE)
    {
        status = (LONG)(FXMAC_MII_BUSY);
    }
    else
    {
        /* Construct mgtcr mask for the operation */
        mgtcr = FXMAC_PHYMNTNC_OP_MASK | FXMAC_PHYMNTNC_OP_W_MASK |
                (phy_address << FXMAC_PHYMNTNC_PHAD_SHFT_MSK) |
                (register_num << FXMAC_PHYMNTNC_PREG_SHFT_MSK) | (u32)phy_data;

        /* Write mgtcr and wait for completion */
        FXMAC_WRITEREG32(instance_p->config.base_address,
                         FXMAC_PHYMNTNC_OFFSET, mgtcr);

        do
        {
            ipisr = FXMAC_READREG32(instance_p->config.base_address,
                                    FXMAC_NWSR_OFFSET);
            ip_write_temp = ipisr;
        } while ((ip_write_temp & FXMAC_NWSR_MDIOIDLE_MASK) == 0x00000000U);

        status = (LONG)(FT_SUCCESS);
    }
    return status;
}

/*****************************************************************************/
/**
* Read the current value of the PHY register indicated by the phy_address and
* the register_num parameters. The MAC provides the driver with the ability to
* talk to a PHY that adheres to the Media Independent Interface (MII) as
* defined in the IEEE 802.3 standard.
*
* Prior to PHY access with this function, the user should have setup the MDIO
* clock with XEmacPs_SetMdioDivisor().
*
* @param instance_p is a pointer to the XEmacPs instance to be worked on.
* @param phy_address is the address of the PHY to be read (supports multiple
*        PHYs)
* @param register_num is the register number, 0-31, of the specific PHY register
*        to read
* @param phydat_aptr is an output parameter, and points to a 16-bit buffer into
*        which the current value of the register will be copied.
*
* @return
*
* - FT_SUCCESS if the PHY was read from successfully
* - FXMAC_MII_BUSY if there is another PHY operation in progress
*
* @note
*
* This function is not thread-safe. The user must provide mutually exclusive
* access to this function if there are to be multiple threads that can call it.
*
* There is the possibility that this function will not return if the hardware
* is broken (i.e., it never sets the status bit indicating that the read is
* done). If this is of concern to the user, the user should provide a mechanism
* suitable to their needs for recovery.
*
* For the duration of this function, all host interface reads and writes are
* blocked to the current XEmacPs instance.
*
******************************************************************************/
LONG FXmacPhyRead(FXmac *instance_p, u32 phy_address,
                  u32 register_num, u16 *phydat_aptr)
{
    u32 mgtcr;
    volatile u32 ipisr;
    u32 IpReadTemp;
    LONG status;

    FT_ASSERTNONVOID(instance_p != NULL);

    /* Make sure no other PHY operation is currently in progress */
    if ((!(FXMAC_READREG32(instance_p->config.base_address,
                           FXMAC_NWSR_OFFSET) &
           FXMAC_NWSR_MDIOIDLE_MASK)) == TRUE)
    {
        status = (LONG)(FXMAC_MII_BUSY);
    }
    else
    {

        /* Construct mgtcr mask for the operation */
        mgtcr = FXMAC_PHYMNTNC_OP_MASK | FXMAC_PHYMNTNC_OP_R_MASK |
                (phy_address << FXMAC_PHYMNTNC_PHAD_SHFT_MSK) |
                (register_num << FXMAC_PHYMNTNC_PREG_SHFT_MSK);

        /* Write mgtcr and wait for completion */
        FXMAC_WRITEREG32(instance_p->config.base_address,
                         FXMAC_PHYMNTNC_OFFSET, mgtcr);

        do
        {
            ipisr = FXMAC_READREG32(instance_p->config.base_address,
                                    FXMAC_NWSR_OFFSET);
            IpReadTemp = ipisr;
        } while ((IpReadTemp & FXMAC_NWSR_MDIOIDLE_MASK) == 0x00000000U);

        /* Read data */
        *phydat_aptr = (u16)FXMAC_READREG32(instance_p->config.base_address,
                                            FXMAC_PHYMNTNC_OFFSET);
        status = (LONG)(FT_SUCCESS);
    }
    return status;
}